#include "useTutorialAnalysis.hxx"
#include "FiducialVolumeDefinition.hxx"
#include "Parameters.hxx"
#include "tutorialSelection.hxx"
#include "tutorialBranchesSelection.hxx"
#include "tutorialCorrection.hxx"
#include "tutorialWeightSystematics.hxx"
#include "tutorialVariationSystematics.hxx"
#include "CategoriesUtils.hxx"
#include "BasicUtils.hxx"


/*  
    This is an example of how to use several existing analyses in our analysis.
    In this way we can for example add to the micro-tree variables that are already defined in other analyses. 

    To avoid major modifications in AnalysisAlgorithm several workarounds has been taken. 
    The functionality below will improve (and made easier) once we have clearer ideas about what we want
*/

//********************************************************************
useTutorialAnalysis::useTutorialAnalysis(AnalysisAlgorithm* ana) : AnalysisAlgorithm(ana) {
//********************************************************************

  // Minimum accum level to save event into the output Micro-trees
  SetMinAccumCutLevelToSave(ND::params().GetParameterI("tutorialAnalysis.MinAccumLevelToSave"));

  // Minimum accum level to save event into the output RooTrackerTree
  SetMinAccumCutLevelToSaveRooTracker(ND::params().GetParameterI("tutorialAnalysis.MinAccumLevelToSaveRooTracker"));

  // Create a tutorialAnalysis passing this analysis to the constructor. In that way the same managers are used
  _tutorialAnalysis = new tutorialAnalysis(this);

  // Use the tutorialAnalysis (in practice that means that the same box and event will be used for the tutorialAnalysis as for this analysis)
  UseAnalysis(_tutorialAnalysis);

  // Create a nueCCAnalysis passing this analysis to the constructor. In that way the same managers are used
  _nueCCAnalysis = new nueCCAnalysis(this);

  // Use the nueCCAnalysis (in practice that means that the same box and event will be used for the nueCCAnalysis as for this analysis)
  UseAnalysis(_nueCCAnalysis);
  
  // Add the package version (to be stored in the "config" tree)
  ND::versioning().AddPackage("tutorialAnalysis", anaUtils::GetSoftwareVersionFromPath((std::string)getenv("TUTORIALANALYSISROOT")));
}

//********************************************************************
void useTutorialAnalysis::DefineSelections(){
//********************************************************************

  // Define the selections of tutorialAnalysis
  _tutorialAnalysis->DefineSelections();

  // Define the selections of nueCCAnalysis
  _nueCCAnalysis->DefineSelections();
}

//********************************************************************
void useTutorialAnalysis::DefineCorrections(){
//********************************************************************

  // Define the corrections of tutorialAnalysis
  _tutorialAnalysis->DefineCorrections();

  // Define the corrections of nueCCAnalysis
  _nueCCAnalysis->DefineCorrections();
}

//********************************************************************
void useTutorialAnalysis::DefineSystematics(){
//********************************************************************

  // Define the systematics of tutorialAnalysis
  _tutorialAnalysis->DefineSystematics();

  // Define the systematics of nueCCAnalysis
  // The system complains when this line is uncommented because the systematics in baseAnalysis are added twice. 
  // We need modifications in AnalysisAlgorithm to avoid that
  //  _nueCCAnalysis->DefineSystematics();
}

//********************************************************************
void useTutorialAnalysis::DefineConfigurations(){
//********************************************************************

  // Define the configurations of tutorialAnalysis
  _tutorialAnalysis->DefineConfigurations();

  // Define the configurations of nueCCAnalysis
  _nueCCAnalysis->DefineConfigurations();
}

//********************************************************************
void useTutorialAnalysis::DefineMicroTrees(bool addBase){
//********************************************************************

  // Add all variables in tutorialAnalysis
  _tutorialAnalysis->DefineMicroTrees(addBase);

  // Add all variables in nueCCAnalysis
  _nueCCAnalysis->DefineMicroTrees(false);

  // Add some extra variables to the micro-trees
  AddVar4VF(output(), selmu_endpos,     "muon candidate reconstructed end position");
}

//********************************************************************
void useTutorialAnalysis::DefineTruthTree(){
//********************************************************************

  // Add all variables of tutorialAnalysis
  _tutorialAnalysis->DefineTruthTree();

  // Add all variables of nueCCAnalysis
  _nueCCAnalysis->DefineTruthTree();
}

//********************************************************************
bool useTutorialAnalysis::Process(){
//********************************************************************

  /*  
      Since each of the three selections use a different box we need to give the appropriate one in each case. 
      The index in the method box() should much the order in which selections where added. 
      This will improve in the future ...
  */

  bool ok1 = sel().ApplySelection("kTrackerTutorial",        *_event, box(0));
  bool ok2 = sel().ApplySelection("kTrackerTutorialBranches",*_event, box(1));
  bool ok3 = sel().ApplySelection("kFGD1NuECC",              *_event, box(2));

  // Return true if any of the two selections is passed
  return (ok1 || ok2 || ok3);
}

//********************************************************************
void useTutorialAnalysis::FillMicroTrees(bool addBase){
//********************************************************************

  // Fill all variables in tutorialAnalysis  
  _tutorialAnalysis->FillMicroTrees(addBase);  

  // Fill all variables in nueCCAnalysis
  SetSelectedSelection(2);  // We need this line to tell _nueCCAnalysis->FillMicroTrees() which box should be used
  _nueCCAnalysis->FillMicroTrees(false);  
  SetSelectedSelection(0);

  // Fill the extra variable
  if (box().HMNtrack){
    output().FillVectorVarFromArray(selmu_endpos, box().HMNtrack->PositionEnd, 4);
  }
}

//********************************************************************
void useTutorialAnalysis::FillToyVarsInMicroTrees(bool addBase){
//********************************************************************

  // Fill all variables in tutorialAnalysis  
  _tutorialAnalysis->FillToyVarsInMicroTrees(addBase);  

  // Fill all variables in nueCCAnalysis  
  _nueCCAnalysis->FillToyVarsInMicroTrees(false);  
}

//********************************************************************
bool useTutorialAnalysis::CheckFillTruthTree(const AnaTrueVertex& vtx){
//********************************************************************

  return (_tutorialAnalysis->CheckFillTruthTree(vtx) || _nueCCAnalysis->CheckFillTruthTree(vtx));
}

//********************************************************************
bool useTutorialAnalysis::CheckFillRooTracker(const AnaTrueVertex& vtx){
//********************************************************************

  return (_tutorialAnalysis->CheckFillRooTracker(vtx) || _nueCCAnalysis->CheckFillRooTracker(vtx));
}

//********************************************************************
void useTutorialAnalysis::FillTruthTree(const AnaTrueVertex& vtx){
//********************************************************************

  // Fill all variables in tutorialAnalysis  
  _tutorialAnalysis->FillTruthTree(vtx);

  // Fill all variables in nueCCAnalysis  
  _nueCCAnalysis->FillTruthTree(vtx);
}

//********************************************************************
void useTutorialAnalysis::FillCategories(){
//********************************************************************

  // Fill categories in tutorialAnalysis  
  _tutorialAnalysis->FillCategories();

  // Fill all variables in nueCCAnalysis  
  SetSelectedSelection(2);  // We need this line to tell _nueCCAnalysis->FillCategories() which box should be used
  _nueCCAnalysis->FillCategories();
  SetSelectedSelection(0);

}
